#include "AsynLogger.h"

void mylog::AsynLogger::Push(const char* data, size_t len) {
    // 1.先对生产者缓冲区进行加锁
    std::unique_lock<std::mutex> ulk(_mtx_pro_buf);
    // 2.进行条件判断，如果生产者缓冲区空间足够则进行写入，否则就阻塞在生产者条件变量上面
    if (_type == ASYNCTYPE::ASYNC_SAFE) {
        _cond_pro.wait(ulk,[&]() { return _pro_buf.WriteableSize() >= len; });
    } else if (_pro_buf.WriteableSize() < len) {
        // 对于 ASYNC_UN_SAFE 模式，扩展缓冲区
        _pro_buf.Resize(len);
    }
    // 3.条件满足，进行数据写入
    _pro_buf.Push(data, len);
    ulk.unlock();
    // 4.写入完毕，通知消费者进行数据处理
    _cond_con.notify_one();
}

void mylog::AsynLogger::ThreadEntry() {
    while (!_stop) {
        {
            // 判断生产者缓冲区是否有数据，有则进行交换，无则在消费者者条件变量上面进行等待
            std::unique_lock<std::mutex> ulk(_mtx_pro_buf);
            // 如果_stop为真，也可以进行向下运行，为了保证数据能够写入完毕以后再进行退出
            _cond_con.wait(ulk, [&]() { return _stop || _pro_buf.ReadableSize() > 0; }); //这个方法会让当前线程等待，直到条件变量被通知。
            // 退出标志被设置且生产者缓冲区没有数据，才可以退出
            if (_stop && _pro_buf.Empty()) break;
            _pro_buf.swap(_con_buf);
        }
        // 2. 通知生产者进行数据写入
        if (_type == ASYNCTYPE::ASYNC_SAFE) _cond_pro.notify_all();
        // 3. 消费者开始进行数据处理
        try {
            _call_back(_con_buf);
        } catch (const std::exception& e) {
            std::cerr << "Callback error: " << e.what() << std::endl;
        }
        // 4. 数据处理完毕，重新初始化消费缓冲区
        _con_buf.reset();
    }
}

void mylog::AsynLogger::Stop() {
    _stop = true;
    _cond_con.notify_all(); // 唤醒异步线程，进行退出
    try {
        if(_td.joinable())_td.join();
    } catch (const std::system_error& e) {
        std::cerr << "Error joining thread: " << e.what() << std::endl;
    }
}

/*
#include <iostream>
void testAsynLogger {
    mylog::AsynLogger::ptr lopper =
        std::make_shared<mylog::AsynLogger>([](mylog::Buffer& buf) {
            std::cout << "Callback called with buffer size: "
                      << buf.ReadableSize() << std::endl;
        });
    char data[] = "Hello, World!";
    lopper->Push(data, strlen(data));
    // 为了让异步线程有机会处理数据，需要一些等待时间
    std::this_thread::sleep_for(std::chrono::seconds(1));
    lopper->Stop();
    return 0;
}
*/